﻿// <copyright file="ListViewSorter.cs" company="Soumya Chattopadhyay">
// Copyright (c) 2010 All Right Reserved
// </copyright>
// <disclaimer> This software is intented for educational purposes only and not for 
// commerical or prodution use. The software is provided "as is", without warranty 
// of any kind, express or implied, including but not limited to the warranties of 
// merchantability, fitness for a particular purpose and noninfringement. In no event 
// shall the author(s) or copyright holder(s) be liable for any claim, damages or other 
// liability, whether in an action of contract, tort or otherwise, arising from, out of 
// or in connection with the software or the use or other dealings in the software.
// </disclaimer>

namespace My.CodePlex.TFSExplorer
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Web.Services.Description;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using My.CodePlex.TFSExplorer.TeamFoundation;

    /// <summary>
    /// The list view sorter
    /// </summary>
    public static class ListViewSorter
    {
        #region Fields

        /// <summary>
        /// The custom sorter dependency property
        /// </summary>
        public static readonly DependencyProperty CustomListViewSorterProperty = DependencyProperty.RegisterAttached("CustomListViewSorter", typeof(string), typeof(ListViewSorter), new FrameworkPropertyMetadata(string.Empty, new PropertyChangedCallback(OnRegisterSortableGrid)));
        
        /// <summary>
        /// Save the definitions
        /// </summary>
        private static Dictionary<string, ListViewSortItem> listViewDefinitions = new Dictionary<string, ListViewSortItem>();

        #endregion

        #region DependencyProperties
        
        #region IsCustomListViewSorter

        /// <summary>
        /// Gets the custom list view sorter
        /// </summary>
        /// <param name="obj">The dependency object</param>
        /// <returns>The string</returns>
        public static string GetCustomListViewSorter(DependencyObject obj)
        {
            return (string)obj.GetValue(CustomListViewSorterProperty);
        }

        /// <summary>
        /// Sets the custom list view sorter.
        /// </summary>
        /// <param name="obj">The dependency object</param>
        /// <param name="value">The value.</param>
        public static void SetCustomListViewSorter(DependencyObject obj, string value)
        {
            obj.SetValue(CustomListViewSorterProperty, value);
        }
        #endregion

        #endregion

        #region Public methods

        /// <summary>
        /// Grids the view column header clicked handler.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        public static void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e)
        {
            ListView view = sender as ListView;
            if (view == null) 
            { 
                return; 
            }

            ListViewSortItem listViewSortItem = listViewDefinitions.ContainsKey(view.Name) ? listViewDefinitions[view.Name] : null;
            if (listViewSortItem == null) 
            { 
                return; 
            }

            GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
            if (headerClicked == null) 
            { 
                return; 
            }

            ListCollectionView collectionView = CollectionViewSource.GetDefaultView(view.ItemsSource) as ListCollectionView;
            if (collectionView == null) 
            { 
                return; 
            }

            ListSortDirection sortDirection = GetSortingDirection(headerClicked, listViewSortItem);

            // Get header name
            string header = string.Empty;

            if (headerClicked.Column.DisplayMemberBinding != null)
            {
                header = (headerClicked.Column.DisplayMemberBinding as System.Windows.Data.Binding).Path.Path as string;
            }
            else
            {
                header = headerClicked.Column.Header as string;
            }

            if (String.IsNullOrEmpty(header)) 
            { 
                return; 
            }

            // sort listview
            if (listViewSortItem.Comparer != null)
            {
                listViewSortItem.Comparer.SortBy = header;
                listViewSortItem.Comparer.SortDirection = sortDirection;
                collectionView.CustomSort = listViewSortItem.Comparer;
                view.Items.Refresh();
            }
            else
            {
                view.Items.SortDescriptions.Clear();
                view.Items.SortDescriptions.Add(new SortDescription(headerClicked.Column.Header.ToString(), sortDirection));
                view.Items.Refresh();
            }

            // change datatemplate of previous and current column header
            headerClicked.Column.HeaderTemplate = GetHeaderColumnsDataTemplate(view, listViewSortItem, sortDirection);

            // Set current sort values as last sort values
            listViewSortItem.LastColumnHeaderClicked = headerClicked;
            listViewSortItem.LastSortDirection = sortDirection;
        }

        #endregion

        #region Private methods

        /// <summary>
        /// Called when [register sortable grid].
        /// </summary>
        /// <param name="obj">The dependency object</param>
        /// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnRegisterSortableGrid(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            // Check if we are in design mode, if so don't do anything.
            if ((bool)DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue)
            {
                return;
            }

            ListView view = obj as ListView;

            if (view != null)
            {
                listViewDefinitions.Add(view.Name, new ListViewSortItem(System.Activator.CreateInstance(Type.GetType(GetCustomListViewSorter(obj))) as IListViewCustomComparer, null, ListSortDirection.Ascending));
                view.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(GridViewColumnHeaderClickedHandler));
            }
        }

        /// <summary>
        /// Gets the header columns data template.
        /// </summary>
        /// <param name="view">The list view</param>
        /// <param name="listViewSortItem">The list view sort item</param>
        /// <param name="sortDirection">The sort direction</param>
        /// <returns>The data template</returns>
        private static DataTemplate GetHeaderColumnsDataTemplate(ListView view, ListViewSortItem listViewSortItem, ListSortDirection sortDirection)
        {
            // remove mark from previous sort column
            if (listViewSortItem.LastColumnHeaderClicked != null)
            {
                listViewSortItem.LastColumnHeaderClicked.Column.HeaderTemplate = view.TryFindResource("ListViewHeaderTemplateNoSorting") as DataTemplate;
            }

            // set correct mark to current column
            switch (sortDirection)
            {
                case ListSortDirection.Ascending:
                    return view.TryFindResource("ListViewHeaderTemplateAscendingSorting") as DataTemplate;
                case ListSortDirection.Descending:
                    return view.TryFindResource("ListViewHeaderTemplateDescendingSorting") as DataTemplate;
                default:
                    return null;
            }
        }

        /// <summary>
        /// Gets the sorting direction.
        /// </summary>
        /// <param name="headerClicked">The header clicked.</param>
        /// <param name="listViewSortItem">The list view sort item.</param>
        /// <returns>The sort direction</returns>
        private static ListSortDirection GetSortingDirection(GridViewColumnHeader headerClicked, ListViewSortItem listViewSortItem)
        {
            if (headerClicked != listViewSortItem.LastColumnHeaderClicked)
            {
                return ListSortDirection.Ascending;
            }
            else
            {
                return (listViewSortItem.LastSortDirection == ListSortDirection.Ascending) ? ListSortDirection.Descending : ListSortDirection.Ascending;
            }
        }

        #endregion
    }
}
